package com.zerocarbon.framework.core.utils;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.Map;

/**
 * Spring应用上下文工具类
 * @author wyf
 * 2020年5月30日
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
	
	/**
	 * 全局ApplicationContext对象
	 */
	public static ApplicationContext applicationContext;
	
    private static ApplicationContext parentApplicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
    	SpringContextUtil.applicationContext = applicationContext;
    }
    
    /**
	 * 获取ApplicationContext对象
	 */
	public ApplicationContext getApplicationContext(){
		return applicationContext;
	}
    
    public static void setContext(ApplicationContext ctx) {
        Assert.notNull(ctx, "SpringContextUtil injection ApplicationContext is null");
        applicationContext = ctx;
        parentApplicationContext = ctx.getParent();
    }

    /**
	 * 获取spring上下文静态方法
	 * @return
	 */
	public static ApplicationContext getContext(){
		return applicationContext;
	}

	/**
	 * 通过上下文获取bean的静态方法
	 * @param name
	 * @return
	 */
	public static Object getBean(String name) {
		Assert.hasText(name, "SpringUtil name is null or empty");
        try {
            return applicationContext.getBean(name);
        } catch (Exception e) {
            return parentApplicationContext.getBean(name);
        }
	}
	
	/**
	 * 通过ApplicationContext获取bean
	 */
    public static <T> T getBean(Class<T> type) {
        Assert.notNull(type, "SpringUtil type is null");
        try {
            return applicationContext.getBean(type);
        } catch (Exception e) {
            return parentApplicationContext.getBean(type);
        }
    }
	
    public static <T> T getBean(String name, Class<T> type) {
        Assert.hasText(name, "SpringUtil name is null or empty");
        Assert.notNull(type, "SpringUtil type is null");
        try {
            return applicationContext.getBean(name, type);
        } catch (Exception e) {
            return parentApplicationContext.getBean(name, type);
        }
    }    

    public static <T> Map<String, T> getBeansOfType(Class<T> type) {
        Assert.notNull(type, "SpringUtil type is null");
        try {
            return applicationContext.getBeansOfType(type);
        } catch (Exception e) {
            return parentApplicationContext.getBeansOfType(type);
        }
    }
    
    public static String getProperty(String key) {
        return applicationContext.getBean(Environment.class).getProperty(key);
    }
    
    public static void publishEvent(Object event) {
        applicationContext.publishEvent(event);
    }
}
